﻿// Inner Fire 游戏引擎库
// DxPass 渲染器初始化功能
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于DirectX的渲染器。
// 此文件分装用于初始化功能
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-04-23

#include "dx_pass.h"
#include "dx_graphics.h"
#include <game/core/timer.h>

namespace ifire::dx {
DxPass::DxPass(DxGraphics* dx) : DxModule(dx) {}

void DxPass::InitConfig() {
  // 雾效
  auto& fog = dx_->Config()["Fog"];
  main_pass_.FogColor = fog("Color");
  main_pass_.gFogStart = fog("Start");
  main_pass_.gFogRange = fog("Range");
}

void DxPass::UpdateMain() {
  XMMATRIX view = XMLoadFloat4x4(&dx_->GetView().GetView());
  XMMATRIX proj = XMLoadFloat4x4(&dx_->GetView().GetProjection());

  XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  auto det = XMMatrixDeterminant(view);
  XMMATRIX invView = XMMatrixInverse(&det, view);
  det = XMMatrixDeterminant(proj);
  XMMATRIX invProj = XMMatrixInverse(&det, proj);
  det = XMMatrixDeterminant(viewProj);
  XMMATRIX invViewProj = XMMatrixInverse(&det, viewProj);

  // Transform NDC space [-1,+1]^2 to texture space [0,1]^2
  XMMATRIX T(                  //
      0.5f, 0.0f, 0.0f, 0.0f,  //
      0.0f, -0.5f, 0.0f, 0.0f, //
      0.0f, 0.0f, 1.0f, 0.0f,  //
      0.5f, 0.5f, 0.0f, 1.0f);
  XMMATRIX viewProjTex = XMMatrixMultiply(viewProj, T);

  XMMATRIX shadowTransform =
      XMLoadFloat4x4(&dx_->GetShadows().GetShadowTransform());

  XMStoreFloat4x4(&main_pass_.View, XMMatrixTranspose(view));
  XMStoreFloat4x4(&main_pass_.InvView, XMMatrixTranspose(invView));
  XMStoreFloat4x4(&main_pass_.Proj, XMMatrixTranspose(proj));
  XMStoreFloat4x4(&main_pass_.InvProj, XMMatrixTranspose(invProj));

  // VP矩阵在两个Pass里面有用。
  XMStoreFloat4x4(&main_pass_.ViewProj, XMMatrixTranspose(viewProj));

  XMStoreFloat4x4(&main_pass_.InvViewProj, XMMatrixTranspose(invViewProj));
  XMStoreFloat4x4(&main_pass_.ViewProjTex, XMMatrixTranspose(viewProjTex));
  XMStoreFloat4x4(
      &main_pass_.ShadowTransform, XMMatrixTranspose(shadowTransform));
  main_pass_.EyePosW = dx_->GetView().GetEyePos();
  main_pass_.RenderTargetSize =
      XMFLOAT2((float)dx_->GetWidth(), (float)dx_->GetHeight());
  main_pass_.InvRenderTargetSize =
      XMFLOAT2(1.0f / dx_->GetWidth(), 1.0f / dx_->GetHeight());
  main_pass_.NearZ = 1.0f;
  main_pass_.FarZ = 1000.0f;
  main_pass_.TotalTime = game::g_timer.TotalTime();
  main_pass_.DeltaTime = game::g_timer.DeltaTime();
  main_pass_.AmbientLight = {0.1f, 0.1f, 0.2f, 1.0f};

  // 上传数据
  auto currPassCB = dx_->CurrentFrameRes()->pass_cb.get();
  currPassCB->CopyData(dx_->CurrentFrameRes()->MainPassIndex(), main_pass_);
}

void DxPass::UpdateSsao() {
  SsaoConstants ssaoCB;
  auto ssao = dx_->GetPostProcessing().GetSsao();

  XMMATRIX P = XMLoadFloat4x4(&dx_->GetView().GetProjection());

  // 将NDC的空间从[-1,+1]^2 转换到 [0,1]^2
  XMMATRIX T(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
      0.0f, 0.5f, 0.5f, 0.0f, 1.0f);

  ssaoCB.Proj = main_pass_.Proj;
  ssaoCB.InvProj = main_pass_.InvProj;
  XMStoreFloat4x4(&ssaoCB.ProjTex, XMMatrixTranspose(P * T));

  ssao->GetOffsetVectors(ssaoCB.OffsetVectors);

  auto blurWeights = ssao->CalcGaussWeights(2.5f);
  ssaoCB.BlurWeights[0] = XMFLOAT4(&blurWeights[0]);
  ssaoCB.BlurWeights[1] = XMFLOAT4(&blurWeights[4]);
  ssaoCB.BlurWeights[2] = XMFLOAT4(&blurWeights[8]);

  ssaoCB.InvRenderTargetSize =
      XMFLOAT2(1.0f / ssao->SsaoMapWidth(), 1.0f / ssao->SsaoMapHeight());

  // Coordinates given in view space.
  ssaoCB.OcclusionRadius = 0.5f;
  ssaoCB.OcclusionFadeStart = 0.2f;
  ssaoCB.OcclusionFadeEnd = 1.0f;
  ssaoCB.SurfaceEpsilon = 0.05f;

  auto currSsaoCB = dx_->CurrentFrameRes()->ssao_cb.get();
  currSsaoCB->CopyData(0, ssaoCB);
}

} // namespace ifire::dx